﻿namespace Sage.WindowsHotKey.Exceptions
{
    /// <summary>
    /// 提供将按键字符串解析为Keys枚举值的功能
    /// 支持单键和组合键的解析，例如："A"、"Ctrl + A"、"Ctrl + Shift + F1"
    /// </summary>
    public static class KeysStringParser
    {
        /// <summary>
        /// 将按键字符串转换为Keys值
        /// </summary>
        /// <param name="keyString">按键字符串，可以是单键("A")或组合键("Ctrl + A")</param>
        /// <param name="separator">组合键的分隔符，默认为 "+"</param>
        /// <returns>对应的Keys值</returns>
        /// <exception cref="ArgumentException">当输入的字符串格式不正确时抛出</exception>
        public static Keys ParseKeyString(string keyString, string separator = "+")
        {
            if (string.IsNullOrWhiteSpace(keyString))
                throw new ArgumentException("按键字符串不能为空", nameof(keyString));

            // 处理分隔符
            separator = separator?.Trim() ?? "+";

            // 清理输入字符串
            keyString = keyString.Trim();

            // 检查是否为单键
            if (!keyString.Contains(separator))
            {
                return ParseKeyPart(keyString);
            }

            // 处理组合键
            var parts = keyString.Split([separator], StringSplitOptions.RemoveEmptyEntries)
                                .Select(p => p.Trim())
                                .Where(p => !string.IsNullOrWhiteSpace(p))
                                .ToList();

            if (parts.Count == 0)
                throw new ArgumentException("无法识别的按键格式", nameof(keyString));

            Keys result = Keys.None;
            bool hasMainKey = false;

            foreach (var part in parts)
            {
                var currentKey = ParseKeyPart(part);

                // 对于非修饰键，确保只有一个
                if ((currentKey & Keys.Modifiers) == Keys.None)
                {
                    if (hasMainKey)
                        throw new ArgumentException($"不能包含多个非修饰键: {keyString}");
                    hasMainKey = true;
                }

                result |= currentKey;
            }

            return result;
        }

        /// <summary>
        /// 解析单个按键部分
        /// 支持修饰键、数字键、特殊符号键以及其他按键的解析
        /// </summary>
        /// <param name="keyPart">要解析的按键字符串部分</param>
        /// <returns>解析后的Keys枚举值</returns>
        /// <exception cref="ArgumentException">当按键部分为空或无法识别时抛出</exception>
        private static Keys ParseKeyPart(string keyPart)
        {
            if (string.IsNullOrWhiteSpace(keyPart))
                throw new ArgumentException("按键部分不能为空");

            return keyPart.ToLower() switch
            {
                "ctrl" or "control" => Keys.Control,
                "alt" => Keys.Alt,
                "shift" => Keys.Shift,
                "0" => Keys.D0,
                "1" => Keys.D1,
                "2" => Keys.D2,
                "3" => Keys.D3,
                "4" => Keys.D4,
                "5" => Keys.D5,
                "6" => Keys.D6,
                "7" => Keys.D7,
                "8" => Keys.D8,
                "9" => Keys.D9,
                "-" => Keys.OemMinus,
                "+" => Keys.Oemplus,
                "[" => Keys.OemOpenBrackets,
                "]" => Keys.OemCloseBrackets,
                "." => Keys.OemPeriod,
                "," => Keys.Oemcomma,
                ";" => Keys.OemSemicolon,
                "'" => Keys.OemQuotes,
                "`" => Keys.Oemtilde,
                "\\" => Keys.OemBackslash,
                "space" => Keys.Space,
                _ => ParseEnumKey(keyPart.ToLower())
            };
        }


        /// <summary>
        /// 尝试将字符串解析为Keys枚举值
        /// </summary>
        /// <param name="keyPart">要解析的按键字符串</param>
        /// <returns>解析后的Keys枚举值</returns>
        /// <exception cref="ArgumentException">当无法将字符串解析为有效的Keys枚举值时抛出</exception>
        /// <remarks>
        /// 此方法用于处理那些未在switch表达式中明确定义的按键。
        /// 它会尝试将输入字符串直接转换为Keys枚举值，支持如下情况：
        /// - 字母键 (A-Z)
        /// - 功能键 (F1-F12)
        /// - 其他特殊键 (Insert, Delete, Home, End 等)
        /// </remarks>
        private static Keys ParseEnumKey(string keyPart)
        {
            try
            {
                // 尝试将字符串解析为Keys枚举值
                // 参数说明：
                // typeof(Keys) - 目标枚举类型
                // keyPart - 要解析的字符串
                // true - 忽略大小写
                return Enum.Parse<Keys>(keyPart, true);
                //return (Keys)Enum.Parse(typeof(Keys), keyPart, true);
            }
            catch (ArgumentException)
            {
                // 当解析失败时，抛出更友好的错误信息
                throw new ArgumentException($"无法识别的按键: {keyPart}");
            }
        }
    }
}
